Introduction to Julia

Let's start with a quick overview of the basic syntax, emphasising differences with Python.

Variables and arithmetic

Numeric values in Julia work similarly to Python:

Variables in Julia are created as in Python, with a simple assignment operation; variable names can be arbitrary unicode characters. Many may be entered in LaTeX notation, using tab substitution: type \alpha<TAB>. There is also tab completion on partial names: \alp<TAB>


In [2]:
x = 3


Out[2]:
3

In [3]:
y = 5


Out[3]:
5

In [5]:
α = 3;  = 10


Out[5]:
10

In [ ]:

Functions use parentheses (round brackets, ()) around the arguments being passed. println prints its arguments, followed by a new line. [print omits the new line.]


In [6]:
println("α = ", α)


α = 3

Simple functions may be defined with a nice mathematical syntax; * is not needed in simple expressions:


In [12]:
f(x) = 2x^2 + 3x + 1
g(x) = f(x) - (2x+1)*(x+1)


Out[12]:
g (generic function with 1 method)

In [9]:
f(3)


Out[9]:
28

In [11]:
g(3.5)


type: g: in apply, expected Function, got Float64
while loading In[11], in expression starting on line 1
 in g at In[10]:2

Variable substitution

The values of variables may be substituted into strings in a simple way using the $ operator:


In [17]:
# Variable substitution with $:
name = "David"
greeting = "Hello, $name"
println(greeting)


Hello, David

More complicated expressions are wrapped in parentheses:


In [13]:
μ = 3
println("The sine of $μ is $(sin(μ))")


The sine of 3 is 0.1411200080598672

Numerical types

There are numerical types with different precisions: typing Float<TAB> or Int<TAB> will provide a list. Currently, in arithmetic calculations types are promoted to the machine type. (This looks likely to change soon.)

Machine integers!


In [15]:
a = int(1e16)
a * 10


Out[15]:
100000000000000000

In [5]:
a = int8(1)
b = int8(2)
a + b


Out[5]:
3

In [6]:
typeof(ans)


Out[6]:
Int64

These promotion rules are defined in int.jl.

Arbitrary-precision arithmetic

Arbitrary-precision integers and floating points are available through the types BigInt and BigFloat. The function big converts a number into the corresponding Big type:


In [16]:
big(10)


Out[16]:
10

In [17]:
typeof(ans)


Out[17]:
BigInt (constructor with 10 methods)

Note that, unlike in Python, integers are not automatically promoted to arbitrary-precision integers.


Exercise: Calculate powers of 10 using standard integers and BigInts



In [18]:
10^5


Out[18]:
100000

In [19]:
10**5


syntax: use "^" instead of "**"
while loading In[19], in expression starting on line 1

In [24]:
10^19


Out[24]:
-8446744073709551616

In [25]:
ten = big(10)


Out[25]:
10

In [27]:
ten^19


Out[27]:
10000000000000000000

In [30]:
i = int8(10)


Out[30]:
10

In [38]:
i * int8(1)


Out[38]:
10

In [39]:
typeof(ans)


Out[39]:
Int64

In [35]:
typemax(Int64)


Out[35]:
9223372036854775807

In [36]:
typemin(Int64)


Out[36]:
-9223372036854775808

Complex numbers

Complex numbers are written using im for the imaginary part:


In [40]:
a = 7
c = (1+3.5im) * a


Out[40]:
7.0 + 24.5im

In [41]:
c.im


Out[41]:
24.5

In [35]:
c.re, c.im


Out[35]:
(7.0,24.5)

In [37]:
c * conj(c)  # conj is a function that returns the conjugate of a complex number


Out[37]:
649.25 + 0.0im

(Tuples behave similarly to Python.)

Rational numbers

Rational numbers are also built into Julia; they are created using the // operator:


In [42]:
3//4


Out[42]:
3//4

In [43]:
typeof(ans)


Out[43]:
Rational{Int64} (constructor with 1 method)

In [49]:
(big(3)//4)^50


Out[49]:
717897987691852588770249//1267650600228229401496703205376

In [50]:
typeof(ans)


Out[50]:
Rational{BigInt} (constructor with 1 method)

In [58]:
3//4 + 5//6


Out[58]:
19//12

Operators are a convenient way of writing functions:


In [51]:
+(3, 4)


Out[51]:
7

In [8]:
//(3, 4)


Out[8]:
3//4

In [52]:
//


Out[52]:
// (generic function with 8 methods)

We see that // is a function, implemented as a series of methods. We can see what these methods are:


In [53]:
methods(//)


Out[53]:
8 methods for generic function //:

In [56]:
3 + -34


Out[56]:
-31

The expression n::Integer is a type annotation that specifies that the method applies when its first argument is of type Integer.

Clicking on the file name takes us directly to the Julia standard library source code on GitHub where these functions are defined!

Vectors: an "equivalent" of Python lists and numpy arrays

To store several values "in one variable", we can try to imitate using a "list" as we would in Python:


In [61]:
l = [3, 4, 5]


Out[61]:
3-element Array{Int64,1}:
 3
 4
 5

In [59]:
typeof(l)


Out[59]:
Array{Int64,1}

In Julia these objects are called Arrays. The curly braces indicate type parameters of the Array type. The first is the type of element contained in the Array (all must be of the same type) and the second the number of dimensions.


Exercise: Try to create an array in this way with elements of different types. What happens?

Exercise: What does the following syntax do?: l = {3, 4, 7.5}



In [62]:
l = [3., 4, 5]


Out[62]:
3-element Array{Float64,1}:
 3.0
 4.0
 5.0

In [64]:
l = [3., "a"]


Out[64]:
2-element Array{Any,1}:
 3.0 
  "a"

In [65]:
l = [3., 'a']


Out[65]:
2-element Array{Float64,1}:
  3.0
 97.0

In [66]:
l = {3., 4, "hello", [3, 4]}


Out[66]:
4-element Array{Any,1}:
 3.0     
 4       
  "hello"
  [3,4]  

Indexing

The indices of Julia arrays are numbered starting at 1, unlike Python (where they are numbered starting at 0).


In [67]:
l[1]


Out[67]:
3.0

The syntax for ranges is similar to that for Python:


In [68]:
l[1:2]


Out[68]:
2-element Array{Any,1}:
 3.0
 4  

However, the limits must be explicitly specified:


In [69]:
l[2:end]   # Use `end` explicitly


Out[69]:
3-element Array{Any,1}:
 4       
  "hello"
  [3,4]  

In [70]:
l[1:end-1]


Out[70]:
3-element Array{Any,1}:
 3.0     
 4       
  "hello"

In [71]:
l[-1]


BoundsError()
while loading In[71], in expression starting on line 1

Julia Arrays, like Python lists, but unlike numpy arrays, are dynamic. However, the syntax is rather different from Python -- to add an element at the end of the list, we write


In [72]:
l = [3,4,5]
l + l


Out[72]:
3-element Array{Int64,1}:
  6
  8
 10

In [74]:
names(l)


Out[74]:
0-element Array{Any,1}

In [75]:
l = [3, 4, 5]

push!(l, 7)


Out[75]:
4-element Array{Int64,1}:
 3
 4
 5
 7

In [ ]:
sizehint

In [76]:
push!


Out[76]:
push! (generic function with 19 methods)

In [77]:
methods(push!)


Out[77]:
19 methods for generic function push!:

In [78]:
methodswith(Array)


Out[78]:
107-element Array{Method,1}:

In [79]:
l = [3, 4, 5]
push!(l, 12.0)


Out[79]:
4-element Array{Int64,1}:
  3
  4
  5
 12

In [80]:
12.0 == 12


Out[80]:
true

In [81]:
push!(l, 12.1)


InexactError()
while loading In[81], in expression starting on line 1
 in push! at array.jl:457

In [ ]:
append!(l, [10, 11, 12])

push! replaces append in Python. There are no methods of objects as in Python; rather, we use functions and send the object as an argument of the function.

The exclamation mark, or bang, (!) indicates that the function modifies its argument; this is a standard convention in Julia.

Arrays which have been defined with a certain type cannot acquire elements of a different type:


In [10]:
l = [3, 4, 5]
push!(l, "hello")


no method convert(Type{Int64}, ASCIIString)
while loading In[10], in expression starting on line 2
 in push! at array.jl:457

Arrays work as mathematical vectors, with the sum of two vectors and scalar multiplication being defined:


In [82]:
a = [1.1, 2.2, 3.3]
b = [4.4, 5.5, 6.6]


Out[82]:
3-element Array{Float64,1}:
 4.4
 5.5
 6.6

In [83]:
a + b


Out[83]:
3-element Array{Float64,1}:
 5.5
 7.7
 9.9

In [84]:
3.5 * a


Out[84]:
3-element Array{Float64,1}:
  3.85
  7.7 
 11.55

However, operators are, in general, not treated in an elementwise fashion (as they would be e.g. in numpy):


In [85]:
a * b


no method *(Array{Float64,1}, Array{Float64,1})
while loading In[85], in expression starting on line 1

Rather, elementwise operations use a Matlab-like syntax, with an extra . before the symbol for the operator:


In [86]:
a .* b


Out[86]:
3-element Array{Float64,1}:
  4.84
 12.1 
 21.78

There are many useful operations on vectors predefined, without needing to explicitly import them.


In [87]:
dot(a,b)  # ans is the last result


Out[87]:
38.72

In [88]:
cross(a, b)


Out[88]:
3-element Array{Float64,1}:
 -3.63
  7.26
 -3.63

In [89]:
norm(a)


Out[89]:
4.115823125451335

Use help or ? (before the command) to obtain help:


In [ ]:
help(dot)

In [ ]:
?dot

In [91]:
transpose(a)


Out[91]:
1x3 Array{Float64,2}:
 1.1  2.2  3.3

In [93]:
a'


Out[93]:
1x3 Array{Float64,2}:
 1.1  2.2  3.3

In [94]:
M = [[2,1], [1,1]]


Out[94]:
4-element Array{Int64,1}:
 2
 1
 1
 1

In [96]:
push!(l, 12.0)


Out[96]:
2x2 Array{Int64,2}:
 2  1
 1  1

In [97]:
M = [2 1; 1 1]


Out[97]:
2x2 Array{Int64,2}:
 2  1
 1  1

In [99]:
M = reshape([1:8], (2,2,2))


Out[99]:
2x2x2 Array{Int64,3}:
[:, :, 1] =
 1  3
 2  4

[:, :, 2] =
 5  7
 6  8

In [102]:
a  b
a × b


Out[102]:
3-element Array{Float64,1}:
 -3.63
  7.26
 -3.63

I used \cdot


In [103]:



Out[103]:
dot (generic function with 7 methods)

[Note that in the Julia command-line REPL, typing ? puts it immediately into a special help mode. Similarly, ; puts it into shell mode, in which commands are sent straight to the shell.]

Control flow: drop the colon (:) and add end

White space in Julia is not significant. Commands on one line can be separated by ;. Blocks must finish with end


In [105]:
i = 0
while i < 5 
    print("$i\t")
    i += 1
end


0	1	2	3	4	

In [107]:
total = 0
for i = 1:10
    total += i
end
println("Sum is $total")


Sum is 55

Here, 1:10 is a range object which may be iterated over.


In [108]:
typeof(1:10)


Out[108]:
UnitRange{Int64} (constructor with 1 method)

We can construct an array from this by enclosing it in square brackets:


In [110]:
collect(1:10)


Out[110]:
10-element Array{Int64,1}:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10

In [111]:
[1:2:10, 17]


Out[111]:
6-element Array{Int64,1}:
  1
  3
  5
  7
  9
 17

Use help or ? to get help:


In [113]:
?dot


Base.dot(x, y)

   Compute the dot product. For complex vectors, the first vector is
   conjugated.

In [114]:
help(dot)


Base.dot(x, y)

   Compute the dot product. For complex vectors, the first vector is
   conjugated.

In [115]:
help("dot")


Base.dot(x, y)

   Compute the dot product. For complex vectors, the first vector is
   conjugated.

Base.LinAlg.BLAS.dot(n, X, incx, Y, incy)

   Dot product of two vectors consisting of "n" elements of array
   "X" with stride "incx" and "n" elements of array "Y" with
   stride "incy".

Exercise: Implement the Babylonian method for calculating the square root of a positive number $y$, via the iteration $$x_{n+1} = \textstyle \frac{1}{2} (x_n + \frac{y}{x_n})$$


In [121]:
 = norm


Out[121]:
norm (generic function with 15 methods)

In [123]:
(a)


Out[123]:
4.115823125451335

In [124]:
snowman(x) = x^2


Out[124]:
snowman (generic function with 1 method)

In [126]:
 = snowman
(3)


Out[126]:
9

Short-circuit evaluation


In [128]:
a = 3
a < 5 && println("Small")   # evaluate the second statement only if the first is true;  semantics of if-then

a > 10 || println("Small")  # semantics of if not-then


Small
Small

In [129]:
a == 3 ? println("Hello") : println("Not true")


Hello

Array comprehensions

There is an equivalent of list comprehensions in Python, as follows. Note that the array construction syntax is quite flexible.


In [132]:
squares = [i^2 for i in [1:2:10, 7]]


Out[132]:
6-element Array{Any,1}:
  1
  9
 25
 49
 81
 49

In [133]:
sums = [i+j for i=1:5, j=1:5]


Out[133]:
5x5 Array{Int64,2}:
 2  3  4  5   6
 3  4  5  6   7
 4  5  6  7   8
 5  6  7  8   9
 6  7  8  9  10

In [134]:
sums = [i+j+k for i=1:5, j=1:5, k=1:5]


Out[134]:
5x5x5 Array{Int64,3}:
[:, :, 1] =
 3  4  5   6   7
 4  5  6   7   8
 5  6  7   8   9
 6  7  8   9  10
 7  8  9  10  11

[:, :, 2] =
 4  5   6   7   8
 5  6   7   8   9
 6  7   8   9  10
 7  8   9  10  11
 8  9  10  11  12

[:, :, 3] =
 5   6   7   8   9
 6   7   8   9  10
 7   8   9  10  11
 8   9  10  11  12
 9  10  11  12  13

[:, :, 4] =
  6   7   8   9  10
  7   8   9  10  11
  8   9  10  11  12
  9  10  11  12  13
 10  11  12  13  14

[:, :, 5] =
  7   8   9  10  11
  8   9  10  11  12
  9  10  11  12  13
 10  11  12  13  14
 11  12  13  14  15

Matrices

Square brackets with commas gives a one-dimensional vector. This is printed in a way that treats it as if it were a column vector (although there is in fact no difference between a one-dimensional row vector and column vector).


In [ ]:
v = [3, 4, 5]

To create explicit matrices, Matlab-style notation is used. If we omit the commas, something different happens: we now obtain a two-dimensional Array, i.e. a matrix, of size $1 \times n$. [Recall that in the standard notation for matrices, an $m \times n$ matrix has $m$ rows and $n$ columns.]


In [ ]:
row_vec = [3 4 5]

We can also use the transpose operator, '. [This is actually the conjugate-transpose operator, which also takes the complex conjugate of complex numbers. Transpose without conjugate is denoted .']


In [ ]:
row_vec = [1im, 2]'

In [ ]:
row_vec = [1im, 2].'

A complete matrix may be constructed using a semicolon (;) to separate rows:


In [135]:
M = [1 2; 3 4]


Out[135]:
2x2 Array{Int64,2}:
 1  2
 3  4

As in numpy, it may also be created using a reshape:


In [ ]:
M = reshape([1, 2, 3, 4], (2,2))

Here, as in Python, (2,2) denotes an (immutable) tuple:


In [ ]:
t = (2, 2)
typeof(t)

There is an important difference in the way that Python and Julia treat slices of matrices. While in Python a one-dimensional slice in either direction returns a 1-dimensional vector, in Julia there is a difference. A vertical one-dimensional slice gives a 1-dimensional vector (a "column vector"):


In [3]:
M[:,1]


Out[3]:
2-element Array{Int64,1}:
 1
 3

However, a horizontal one-dimensional slice produces a $1 \times n$ matrix:


In [5]:
M[1,:]


Out[5]:
1x2 Array{Int64,2}:
 1  2

This is the same result that is produced using the following Matlab-like syntax:


In [6]:
[1 2]


Out[6]:
1x2 Array{Int64,2}:
 1  2

Random numbers

The Mersenne Twister (pseudo-)random number generator is built-in to Julia:


In [136]:
rand()


Out[136]:
0.30176459533546285

In [137]:
rand(5)


Out[137]:
5-element Array{Float64,1}:
 0.322047
 0.858765
 0.744449
 0.932944
 0.735366

In [138]:
x = rand(5, 5)


Out[138]:
5x5 Array{Float64,2}:
 0.718125    0.514504  0.485157  0.118623   0.954479
 0.665983    0.223968  0.571665  0.337021   0.418121
 0.388917    0.989328  0.588583  0.0660616  0.636201
 0.00130766  0.277592  0.476613  0.21       0.171883
 0.0978661   0.499811  0.816341  0.772805   0.207609

In [ ]:
rand

Matrix multiplication


In [139]:
v = [1, 2]


Out[139]:
2-element Array{Int64,1}:
 1
 2

In [140]:
v*v


no method *(Array{Int64,1}, Array{Int64,1})
while loading In[140], in expression starting on line 1

In [17]:
dot(v, v)


Out[17]:
5

In [141]:
M = [2 1; 1 1]


Out[141]:
2x2 Array{Int64,2}:
 2  1
 1  1

In [142]:
dot(M, v)


no method dot(Array{Int64,2}, Array{Int64,1})
while loading In[142], in expression starting on line 1

Matrix multiplication uses the * operator:


In [143]:
M * v


Out[143]:
2-element Array{Int64,1}:
 4
 3

In [144]:
@which M*v


Out[144]:
*{T,S}(A::AbstractArray{T,2},x::AbstractArray{S,1}) at linalg/matmul.jl:71

Exercise: Use the power method to calculate the largest eigenvalue $\lambda_1$ of the matrix $M = \begin{pmatrix} 2 & 1 \\ 1 & 1 \end{pmatrix}$. In this method, we start from an arbitrary non-zero vector $\mathbf{w}$, and repeatedly apply $M$ to it, thus calculating powers of the matrix $M$ applied to $\mathbf{w}$. The resulting vector converges to the eigenvector $\mathbf{v}_1$ corresponding to $\lambda_1$.


In [146]:
w = [1., 1]
M = reshape([2., 1, 1, 1], (2,2))

M, w


Out[146]:
(
2x2 Array{Float64,2}:
 2.0  1.0
 1.0  1.0,

[1.0,1.0])

In [148]:
w0 = [1., 1]
w = copy(w0)

for i in 1:10
    w_new = M*w
    println()


Out[148]:
7 methods for generic function dot:
  • dot{T<:Union(Float64,Float32)}(x::Array{T<:Union(Float64,Float32),1},y::Array{T<:Union(Float64,Float32),1}) at linalg/matmul.jl:32
  • dot{T<:Union(Complex{Float32},Complex{Float64})}(x::Array{T<:Union(Complex{Float32},Complex{Float64}),1},y::Array{T<:Union(Complex{Float32},Complex{Float64}),1}) at linalg/matmul.jl:33
  • dot{T<:Union(Float64,Float32),TI<:Integer}(x::Array{T<:Union(Float64,Float32),1},rx::Union(UnitRange{TI<:Integer},Range{TI<:Integer}),y::Array{T<:Union(Float64,Float32),1},ry::Union(UnitRange{TI<:Integer},Range{TI<:Integer})) at linalg/matmul.jl:35
  • dot{T<:Union(Complex{Float32},Complex{Float64}),TI<:Integer}(x::Array{T<:Union(Complex{Float32},Complex{Float64}),1},rx::Union(UnitRange{TI<:Integer},Range{TI<:Integer}),y::Array{T<:Union(Complex{Float32},Complex{Float64}),1},ry::Union(UnitRange{TI<:Integer},Range{TI<:Integer})) at linalg/matmul.jl:42
  • dot(x::BitArray{1},y::BitArray{1}) at linalg/bitarray.jl:3
  • dot(x::AbstractArray{T,1},y::AbstractArray{T,1}) at linalg/matmul.jl:49
  • dot(x::Number,y::Number) at linalg/matmul.jl:60

In [1]:
for i =1:10
    t = 3
end
t


t not defined
while loading In[1], in expression starting on line 4

Linear algebra

Julia has built-in linear algebra, not only using LAPACK, but now also generic routines that work for arbitrary element types, implemented completely in Julia.

For example, given a matrix $A$, the LU-decomposition of $A$ is equivalent to Gaussian elimination; it expresses $A$ as the product $A = LU$, with $L$ a lower-triangular and $U$ an upper-triangular matrix.

This is implemented in pure Julia for arbitrary element types. When the elements are standard floating-point numbers, it uses the corresponding fast LAPACK implementation.


In [2]:
M = rand(100, 100)
eig(M)


Out[2]:
(Complex{Float64}[49.4553+0.0im,2.60611+1.39241im,2.60611-1.39241im,2.80843+0.0im,1.6786+2.20359im,1.6786-2.20359im,-2.5772+0.722606im,-2.5772-0.722606im,-2.07661+1.73455im,-2.07661-1.73455im  …  0.318764-0.818766im,-0.664996+0.0im,-0.262399+0.696736im,-0.262399-0.696736im,0.631772+0.341774im,0.631772-0.341774im,-0.337579+0.0im,0.0258253+0.441807im,0.0258253-0.441807im,0.244242+0.0im],
100x100 Array{Complex{Float64},2}:
  -0.104506+0.0im   -0.0583494+0.0673774im   …    -0.126245+0.0im
  -0.110228+0.0im   -0.0302002+0.0203231im       0.00971673+0.0im
  -0.106192+0.0im    0.0835864-0.0366953im       -0.0100192+0.0im
  -0.101028+0.0im   -0.0976258-0.0103224im       -0.0208308+0.0im
  -0.109692+0.0im    0.0206091+0.051544im        -0.0373466+0.0im
 -0.0927222+0.0im   0.00469629+0.0464441im   …   -0.0464968+0.0im
  -0.106839+0.0im    0.0021757+0.110256im         -0.116836+0.0im
   -0.10324+0.0im   -0.0737389-0.14787im         -0.0407359+0.0im
  -0.102974+0.0im     -0.11934-0.0301666im        0.0426221+0.0im
  -0.104879+0.0im    0.0237039-0.00547228im     -0.00898699+0.0im
  -0.105285+0.0im   -0.0161691+0.0600921im   …    0.0082313+0.0im
 -0.0995482+0.0im    -0.023878-0.104027im        -0.0274685+0.0im
 -0.0994342+0.0im   -0.0468258-0.044981im        -0.0387807+0.0im
           ⋮                                 ⋱                   
 -0.0954904+0.0im    0.0193279-0.017643im        -0.0780521+0.0im
 -0.0916581+0.0im    -0.066044+0.0354546im        -0.153619+0.0im
 -0.0979165+0.0im     0.101931+0.109964im    …   0.00194682+0.0im
  -0.107172+0.0im    0.0678739-0.0172876im       0.00680776+0.0im
  -0.108272+0.0im    -0.100656+0.00846016im       0.0572358+0.0im
 -0.0913561+0.0im    0.0612352+0.0874928im        0.0822063+0.0im
   -0.10539+0.0im   0.00288259+0.0636149im        -0.151949+0.0im
 -0.0925015+0.0im    0.0304961+0.00627406im  …     0.058312+0.0im
 -0.0966832+0.0im    -0.143995-0.0137428im       -0.0348019+0.0im
  -0.101731+0.0im    0.0519957+0.00597033im      -0.0907889+0.0im
 -0.0896939+0.0im    0.0362903-0.0129214im        -0.035998+0.0im
 -0.0940307+0.0im  -0.00657209-0.158261im        -0.0286019+0.0im)

In [3]:
M = rand(100, 100)
M2 = map(big, M)


Out[3]:
100x100 Array{BigFloat,2}:
 3.41499732256071553138099261559545993804931640625e-01      …  6.689973747130995018750354574876837432384490966796875e-01
 3.837450544904055238504270164412446320056915283203125e-01     7.06782295861154263860726132406853139400482177734375e-01 
 6.73779399891735852889951274846680462360382080078125e-01      8.158750410289050680745503996149636805057525634765625e-01
 6.047191231529878141515155220986343920230865478515625e-01     2.68999012840712481420268886722624301910400390625e-01    
 3.51359116190601117324376900796778500080108642578125e-01      4.960645408074408901910601343843154609203338623046875e-01
 9.30187353346197287606855752528645098209381103515625e-01   …  1.9592681156523372720812403713352978229522705078125e-01  
 4.1193169713166977174978455877862870693206787109375e-01       2.0328662478073766806119238026440143585205078125e-01     
 4.76493709114803376536428913823328912258148193359375e-01      8.88367071632467197872529141022823750972747802734375e-01 
 8.63301451930530650002992842928506433963775634765625e-01      8.21008010717050762394819685141555964946746826171875e-01 
 8.000181339706136096623367848224006593227386474609375e-01     3.88250252605438550546068654512055218219757080078125e-01 
 9.18804371646583906141358966124244034290313720703125e-01   …  9.625508929917956368882414608378894627094268798828125e-01
 1.282382267075459214566990340244956314563751220703125e-01     7.310058552909601825575691691483370959758758544921875e-01
 7.481661838307440692830141415470279753208160400390625e-01     8.349264288870987815727175984648056328296661376953125e-01
 ⋮                                                          ⋱                                                           
 6.45861874198019325632458276231773197650909423828125e-01      2.150989335177075911786914730328135192394256591796875e-01
 8.3047253465137860217737397761084139347076416015625e-02       6.088991389391111841433712470461614429950714111328125e-01
 2.040236468823974913533447761437855660915374755859375e-01  …  4.599328275746004113244680411298759281635284423828125e-01
 2.714502378461052245484097511507570743560791015625e-01        4.2675221731670820446424841065891087055206298828125e-02  
 1.620864883793042832138553421827964484691619873046875e-01     3.81989856583413445179076006752438843250274658203125e-01 
 2.418257277111706127215029482613317668437957763671875e-01     8.273765904860841402523874421603977680206298828125e-01   
 3.297335386996638195711284424760378897190093994140625e-01     7.109467553999271327569431377924047410488128662109375e-01
 3.470167295594233092259628392639569938182830810546875e-01  …  3.512130007274747445222828901023603975772857666015625e-01
 9.44736536917150981906843298929743468761444091796875e-01      1.673222843336221732357671498903073370456695556640625e-01
 6.64031380167859897056814588722772896289825439453125e-01      2.867078930370026146334794248105026781558990478515625e-01
 9.403058098155445687638120944029651582241058349609375e-01     3.503450471039382119187166608753614127635955810546875e-01
 9.909181693511914801320017431862652301788330078125e-02        3.346426606631125455493247500271536409854888916015625e-01

In [4]:
lu(M2)


Out[4]:
(
100x100 Array{BigFloat,2}:
 1e+00                                                                                 …  0e+00
 2.083543061729824728373762137800462284256013864405782072863835894555022090664619e-01     0e+00
 1.885080284248462046020553070941008006804923664109838738230355865657787411698943e-01     0e+00
 4.868390494295089913791749872572274980146677026896154096577236088185654381668904e-02     0e+00
 9.308379963386380414924032310016838399893783533616283757409827477656339899757264e-01     0e+00
 7.588133956951531752045254445901184138969646497514731338899505551158575891805754e-01  …  0e+00
 5.266178057727190424640646456875355137119195255458693197726150378925488423692808e-02     0e+00
 4.122198331411938617095188149651482955907553341364862761717983837869016180082745e-01     0e+00
 4.768270046510868759568943997449232728715348268189695326045702886622947615102341e-01     0e+00
 7.262472956699855818394390561425701183431889871884939446174009974067744265886207e-01     0e+00
 4.897159135606284999904616348894421350490998293172493143200895359578619149888494e-01  …  0e+00
 9.194470525255329080840280015506434074407586269228845733688232051880617161714118e-01     0e+00
 5.669801500437603302447298467648629336522052055004847260931139087801841015280855e-01     0e+00
 ⋮                                                                                     ⋱       
 8.325092743125319340835942125382173714655934178820894611723511198903528745790921e-01     0e+00
 5.99575846903674111184857903426575819578830570089555088149829534780684898565552e-01      0e+00
 4.705556231467836533274560606563136914404622521728411583796835746422943328328811e-01  …  0e+00
 6.323212489337355821222728906633059988391570575895420273365638052373312599449895e-01     0e+00
 6.463136385667993357235802266885210197479961139497370636575989044216656885268521e-01     0e+00
 6.639246083344548585560175933677981700500964740310374618610387738425558764057364e-01     0e+00
 8.310534296002742644810532677088961343742702626588530772056973456646898200119421e-02     0e+00
 9.916112920437880282175608474107770616723639508546054026693021713851416081533574e-02  …  0e+00
 3.965763063951899043726337854001427962884146994697338694105291529592702397043129e-01     0e+00
 2.917545039865275863337548830872652081862746426685795084335557664811870353153899e-01     0e+00
 1.283279261678429695656259848376865161609281298477312170163526263575172451731624e-01     0e+00
 6.104155947547656981543070640316756224786274484114327613922335245871101020336498e-01     1e+00,

100x100 Array{BigFloat,2}:
 9.993010137155982075540805453783832490444183349609375e-01  …   1.409297892572045629577814906951971352100372314453125e-01                           
 0e+00                                                          7.155612742579487919733876206897026954555154722494790178175006242995846468610666e-02
 0e+00                                                          1.132488780580699100510002528411618972832336576259989878404248337011966392263417e-01
 0e+00                                                          4.504778025722529491773090542002751344412324953450690709636621410427196447082819e-02
 0e+00                                                          6.233431183874435415550042456245419324533011989952463879362308281767234829270391e-02
 0e+00                                                      …   3.631318249243016531330675418428314100281126113341942170810688207388790162793761e-01
 0e+00                                                          2.029287842660357900704206599940314822769294458925981922655649869361624248905821e-01
 0e+00                                                          7.52105368229322982795039994345249521629118994902925956161636699630776230007012e-02 
 0e+00                                                          4.406369636761867288461402103539692045041698197934802386166632976306907414893489e-01
 0e+00                                                          4.236933499688602452015765639817015802623579817516729453958923460187283582721779e-01
 0e+00                                                      …   5.197821284519048835667909474793719852300945935946894730205189079214475700368085e-01
 0e+00                                                          1.767829532273192639832024949167781724959068431739050291849191663777594732940454e+00
 0e+00                                                         -9.987903274245042009683043128635229469120006579296449027095594391828438391748962e-01
 ⋮                                                          ⋱                                                                                       
 0e+00                                                          2.452094787545326669056576281040712473855057097800618302606036437896943371809676e+00
 0e+00                                                          2.424224378682565116695054070187176884395872116526132504658693528676021797028345e+00
 0e+00                                                      …   1.739952735261677244657029226964636787527858259639483093286717758727599018899551e-01
 0e+00                                                         -8.338823757841568391102445642643302505644971083904295926224433137281864464662108e-01
 0e+00                                                          1.398597251287204110883566700591731100246330289605303737831397829885026779457033e+00
 0e+00                                                          3.366917820481630468904690865376128629837566610214791987044069972956018723156938e-01
 0e+00                                                          1.416704374725771669069691596767062226456031860333416174335896646898251132981301e+00
 0e+00                                                      …   3.959281560717655532791332979444110794533750161261434478156677622153539426198889e-01
 0e+00                                                         -3.259857916254936358252594908642245701030956594119200324632141166523715083219904e-01
 0e+00                                                         -2.019555266178335762641524496293984004287939828006888972093591266537499585323791e+00
 0e+00                                                          2.742699647804872200069338994881129795068709555988360848668187543705041970312082e+00
 0e+00                                                         -9.746189261340509085756699594195457166548408350827224427205589028301701402738505e-01,

[87,78,62,22,6,42,28,7,8,49  …  14,66,89,68,90,100,39,83,12,43])

In [5]:
lu(M)


Out[5]:
(
100x100 Array{Float64,2}:
 1.0         0.0           0.0        …   0.0        0.0       0.0
 0.208354    1.0           0.0            0.0        0.0       0.0
 0.188508    0.197253      1.0            0.0        0.0       0.0
 0.0486839   0.498701     -0.125564       0.0        0.0       0.0
 0.930838    0.695687     -0.655293       0.0        0.0       0.0
 0.758813   -0.091067      0.561132   …   0.0        0.0       0.0
 0.0526618   0.445214     -0.171587       0.0        0.0       0.0
 0.41222     0.356765     -0.364269       0.0        0.0       0.0
 0.476827    0.107381      0.338406       0.0        0.0       0.0
 0.726247    0.330065      0.340706       0.0        0.0       0.0
 0.489716    0.816836     -0.131986   …   0.0        0.0       0.0
 0.919447    0.50482      -0.930075       0.0        0.0       0.0
 0.56698    -0.112169     -0.128156       0.0        0.0       0.0
 ⋮                                    ⋱                           
 0.832509    0.000309064   0.0840172      0.0        0.0       0.0
 0.599576    0.331331     -0.411492       0.0        0.0       0.0
 0.470556    0.264746     -0.348458   …   0.0        0.0       0.0
 0.632321   -0.0624872     0.68665        0.0        0.0       0.0
 0.646314    0.0203543     0.0349262      0.0        0.0       0.0
 0.663925    0.257865     -0.150108       0.0        0.0       0.0
 0.0831053   0.997736     -0.698928       0.0        0.0       0.0
 0.0991611   0.951318      0.169188   …   0.0        0.0       0.0
 0.396576    0.296518      0.133782       0.0        0.0       0.0
 0.291755    0.26562      -0.185842       1.0        0.0       0.0
 0.128328    0.345751      0.265363      -0.305614   1.0       0.0
 0.610416    0.548097     -0.466394      -0.129163  -0.432331  1.0,

100x100 Array{Float64,2}:
 0.999301  0.269395  0.513937  …   0.965834    0.335865    0.14093  
 0.0       0.890295  0.523864     -0.0298493   0.188389    0.0715561
 0.0       0.0       0.786627      0.659953    0.222307    0.113249 
 0.0       0.0       0.0           0.886482    0.903205    0.0450478
 0.0       0.0       0.0          -0.56174     0.0585484   0.0623343
 0.0       0.0       0.0       …   0.661002    1.0115      0.363132 
 0.0       0.0       0.0           0.46286     0.215562    0.202929 
 0.0       0.0       0.0           0.0655094  -0.591076    0.0752105
 0.0       0.0       0.0          -0.736783    0.138927    0.440637 
 0.0       0.0       0.0           0.206547   -0.0256575   0.423693 
 0.0       0.0       0.0       …  -0.502041   -0.149553    0.519782 
 0.0       0.0       0.0          -1.01702     0.27332     1.76783  
 0.0       0.0       0.0           0.303928   -0.215946   -0.99879  
 ⋮                             ⋱                                    
 0.0       0.0       0.0           2.39772    -3.46131     2.45209  
 0.0       0.0       0.0           0.108893   -1.42097     2.42422  
 0.0       0.0       0.0       …  -3.03719     0.900553    0.173995 
 0.0       0.0       0.0          -4.80897     3.18917    -0.833882 
 0.0       0.0       0.0           2.19005    -1.0208      1.3986   
 0.0       0.0       0.0          -1.26345    -1.21298     0.336692 
 0.0       0.0       0.0          -0.417998    0.544668    1.4167   
 0.0       0.0       0.0       …  -0.670505    1.21561     0.395928 
 0.0       0.0       0.0          -1.59089    -1.34402    -0.325986 
 0.0       0.0       0.0          -3.35482     0.327353   -2.01956  
 0.0       0.0       0.0           0.0         1.52136     2.7427   
 0.0       0.0       0.0           0.0         0.0        -0.974619 ,

[87,78,62,22,6,42,28,7,8,49  …  14,66,89,68,90,100,39,83,12,43])

In [5]:
methods(lu)


Out[5]:
2 methods for generic function lu:

In [7]:
@edit lu(M)

Interacting with the system

Command-line arguments

A Julia script, similar to a Python script, is a sequence of Julia commands placed in a file, with the termination .jl.

From the command line, a script script.jl can be run as

julia script.jl arg1 arg2 

where arg1 and arg2 are command-line arguments.

These command-line arguments to Julia scripts are placed in the variable ARGS as an array of strings.

Files

Simple file input and output is easy:


In [66]:
outfile = open("test.txt", "w")


Out[66]:
IOStream(<file test.txt>)

In [69]:
for i in 1:10
    println(outfile, "The value of i is $i")
end

close(outfile)

In [70]:
;cat test.txt


The value of i is 1
The value of i is 2
The value of i is 3
The value of i is 4
The value of i is 5
The value of i is 6
The value of i is 7
The value of i is 8
The value of i is 9
The value of i is 10

In [72]:
infile = open("test.txt", "r")


Out[72]:
IOStream(<file test.txt>)

In [74]:
lines = readlines(infile)


Out[74]:
10-element Array{Union(UTF8String,ASCIIString),1}:
 "The value of i is 1\n" 
 "The value of i is 2\n" 
 "The value of i is 3\n" 
 "The value of i is 4\n" 
 "The value of i is 5\n" 
 "The value of i is 6\n" 
 "The value of i is 7\n" 
 "The value of i is 8\n" 
 "The value of i is 9\n" 
 "The value of i is 10\n"

In [75]:
map(split, lines)


Out[75]:
10-element Array{Array{SubString{ASCIIString},1},1}:
 SubString{ASCIIString}["The","value","of","i","is","1"] 
 SubString{ASCIIString}["The","value","of","i","is","2"] 
 SubString{ASCIIString}["The","value","of","i","is","3"] 
 SubString{ASCIIString}["The","value","of","i","is","4"] 
 SubString{ASCIIString}["The","value","of","i","is","5"] 
 SubString{ASCIIString}["The","value","of","i","is","6"] 
 SubString{ASCIIString}["The","value","of","i","is","7"] 
 SubString{ASCIIString}["The","value","of","i","is","8"] 
 SubString{ASCIIString}["The","value","of","i","is","9"] 
 SubString{ASCIIString}["The","value","of","i","is","10"]

In [76]:
[float(line[6]) for line in map(split, lines)]


Out[76]:
10-element Array{Any,1}:
  1.0
  2.0
  3.0
  4.0
  5.0
  6.0
  7.0
  8.0
  9.0
 10.0

In [49]:
x = rand(5,5)


Out[49]:
5x5 Array{Float64,2}:
 0.733305  0.407818  0.856017  0.17519   0.300911   
 0.780196  0.410316  0.747914  0.517746  0.482768   
 0.821524  0.282658  0.499362  0.33969   0.46995    
 0.127905  0.784039  0.552099  0.370477  0.000157871
 0.614037  0.831996  0.557765  0.400553  0.816338   

In [54]:
writedlm("random.txt", x)
;cat random.txt


.7333048397971658	.40781770914373294	.8560165670499627	.1751897160302176	.3009107585707549
.7801957216838906	.41031585009227367	.7479144542902101	.5177461965467203	.4827677730696496
.8215243209225078	.28265839467586185	.49936164572625463	.33968997036639403	.46994964345333146
.1279053435465234	.7840390419869261	.5520986105415162	.3704773976502098	.00015787055013616325
.6140369836251944	.8319958406211578	.5577649080752074	.4005532312183908	.8163378474918641

In [56]:
y = readdlm("random.txt")  # note that tab completion works for files


Out[56]:
5x5 Array{Float64,2}:
 0.733305  0.407818  0.856017  0.17519   0.300911   
 0.780196  0.410316  0.747914  0.517746  0.482768   
 0.821524  0.282658  0.499362  0.33969   0.46995    
 0.127905  0.784039  0.552099  0.370477  0.000157871
 0.614037  0.831996  0.557765  0.400553  0.816338   

Shelling out


In [93]:
;ls


Arrays with any indexing.ipynb
Introduction to Julia.ipynb
Introduction to Julia.pdf
Introduction to Julia.tex
Random matrices.ipynb
julia_tutorial.md

In [9]:
run(`echo Hello`)


Hello

Scientific computing

Linear algebra, FFT, random numbers, special functions. Packages for optimization, ODEs etc.

Functions

Functions may be defined using the short syntax f(x) = 3x + 1 or using a longer form:


In [10]:
dup(x) = 2x


Out[10]:
dup (generic function with 1 method)

In [11]:
function duplicate(x)
    2x   # no explicit "return" needed
end


Out[11]:
duplicate (generic function with 1 method)

The last value computed in the function is automatically returned; no explicit return statement is required.


In [19]:
duplicate(x) = x^2


Out[19]:
quad2 (generic function with 1 method)

Every operator in Julia is a function. Functions are implemented by specifying their action on different types. Until now, we have written only functions that are generic, in the sense that they do not specify which type they accept, and as in Python they will work as long as the operations performed in them make sense for the input value:


In [13]:
duplicate(3), duplicate(3.5), duplicate(1+3im)


Out[13]:
(6,7.0,2 + 6im)

In [14]:
duplicate("Hola")


syntax: unexpected ,
while loading In[14], in expression starting on line 1

In [15]:
2 * "Hola"


no method *(Int64, ASCIIString)
while loading In[15], in expression starting on line 1

Note that string concatenation uses the * operator in Julia, instead of the + operator as in Python. Repeating a string is thus done by raising to an integer power:


In [16]:
"Hello"^2


Out[16]:
"HelloHello"

As a simple example, suppose that we wish to concatenate two strings. In Python we would write:


In [17]:
s1 = "Hello, "
s2 = "David"

s1 + s2


no method +(ASCIIString, ASCIIString)
while loading In[17], in expression starting on line 4

However, we see that in Julia, summation is not defined for strings. What is it defined for?


In [20]:
+


Out[20]:
+ (generic function with 123 methods)

We see that + is treated as a function, and that it has a multitude of methods, which, in Julia, are specialised versions of the function that act on different types:


In [107]:
methods(+)


Out[107]:
122 methods for generic function +:

If we were unaware of the * operator for string concatenation, we could just define our own + for the concatenation of two strings:


In [1]:
+(s1::String, s2::String) = string(s1, s2)


Out[1]:
+ (generic function with 124 methods)

In [5]:
"First" + " second"


Out[5]:
"First second"

However, we cannot add a number to a string, since we have not (yet) defined it:


In [2]:
"The value of x is " + 3


no method +(ASCIIString, Int64)
while loading In[2], in expression starting on line 1

This we can also define, using the previous new definition:


In [11]:
+(s::String, x::Number) = s + "$(2x)"


Out[11]:
+ (generic function with 126 methods)

In [12]:
"The value of x is " + 3


Out[12]:
"The value of x is 6"

In [5]:
x = 3.5
"The value of x is " + x


Out[5]:
"The value of x is 3.5"

In [8]:
3 + "hello"


no method +(Int64, ASCIIString)
while loading In[8], in expression starting on line 1

In fact, we can define the summation of a string with any other object:


In [13]:
+(s::String, x) = s + string(x)


Out[13]:
+ (generic function with 126 methods)

In [14]:
"Complex " + [3,4,5]


Out[14]:
"Complex [3,4,5]"

In [15]:
"a" + 3


Out[15]:
"a6"

In [16]:
Number


Out[16]:
Number

In [17]:
typeof(Number)


Out[17]:
DataType

In [18]:
super(Int64)


Out[18]:
Signed

In [19]:
super(Signed)


Out[19]:
Integer

In [20]:
super(Integer)


Out[20]:
Real

In [21]:
super(Real)


Out[21]:
Number

In [22]:
super(Number)


Out[22]:
Any

In this way, the concept of "function" is replaced by a "patchwork" of different definitions for objects of different types, easily modifiable by the user. This is also exactly the way to define "operator overloading" for user-defined types.

In the above, we also begin to see the power of multiple dispatch: we defined two methods (versions) of the function +, both with the same number but different types of arguments.

User-defined types

A user-defined "composite type" is a collection of data. Unlike in Python, types do not "own" methods (functions internal to the type).

Rather, methods are defined separately, and are characterised by the types of all of their arguments; this is known as multiple dispatch. (Dispatch is the process of choosing which "version" of a given function to execute.)

A simple, but useful, example, is that of defining a 2D vector type. (See also the ImmutableArrays.jl package; fixed-size arrays will later be incorporated into base Julia.)


In [26]:
@which 3//4


Out[26]:
//(n::Integer,d::Integer) at rational.jl:17

In [28]:
Rational(3)


Out[28]:
3//1

In [27]:
6//4


Out[27]:
3//2

In [25]:
im*im


Out[25]:
-1 + 0im

In [40]:
immutable Vector2D   # type
    x::Float64
    y::Float64
end

In [32]:
v = Vector2D(3, 4)
w = Vector2D(5, 6)


Out[32]:
Vector2D(5.0,6.0)

In [33]:
v + w


no method +(Vector2D, Vector2D)
while loading In[33], in expression starting on line 1

In [34]:
+(v::Vector2D, w::Vector2D) = Vector2D(v.x+w.x, v.y+w.y)


Out[34]:
+ (generic function with 127 methods)

In [35]:
v + w


Out[35]:
Vector2D(8.0,10.0)

In [36]:
*(v::Vector2D, α::Number) = Vector2D(v.x*α, v.y*α)
*(α::Number, v::Vector2D) = Vector2D(v.x*α, v.y*α)


Out[36]:
* (generic function with 127 methods)

In [37]:
v * 3.5


Out[37]:
Vector2D(10.5,14.0)

In [38]:
3.5 * v


no method *(Float64, Vector2D)
while loading In[38], in expression starting on line 1

Exercise: Define mathematical operations on Vector2D. Define a particle with position and velocity in 2D. Define function move that acts on a particle to move it over a time $\delta t$.

Here, we have used immutable instead of type for efficiency: the object is stored in an efficient packed form.

The equivalent of the Python __repr__ method for an object is to extend the show method:


In [41]:
show


Out[41]:
show (generic function with 89 methods)

In [5]:
import Base.show

show(io::IO, v::Vector2D) = print(io, "[$(v.x), $(v.y)]")


Out[5]:
show (generic function with 90 methods)

In [44]:
v


Out[44]:
[3.0, 4.0]

In [4]:
+(v1::Vector2D, v2::Vector2D) = Vector2D(v1.x+v2.x, v1.y+v2.y)

*(v::Vector2D, lamb::Number)  = Vector2D(lamb*v.x, lamb*v.y)


Out[4]:
* (generic function with 125 methods)

We can confirm that the new method for the function + has indeed been defined:


In [5]:
methods(+)


Out[5]:
128 methods for generic function +:

In [7]:
x = Vector2D(3, 4)
y = Vector2D(5, 6)

x + y


Out[7]:
[8.0, 10.0]

Parametrised types

Types may have a parameter, for example:


In [1]:
immutable Vector2D{T <: Real}
    x::T
    y::T
end

T is a type parameter. The expression T <: Real means that T must be a subtype of the abstract type Real. We can investigate the type hierarchy with the super function:


In [4]:
Integer


Out[4]:
Integer

In [5]:
super(Integer)


Out[5]:
Real

In [6]:
super(Real)


Out[6]:
Number

In [7]:
super(Number)


Out[7]:
Any

In [2]:
v = Vector2D(3., 4.)


Out[2]:
Vector2D{Float64}(3.0,4.0)

In [3]:
v = Vector2D(3, 4.)


no method Vector2D{T<:Real}(Int64, Float64)
while loading In[3], in expression starting on line 1

In [4]:
v = Vector2D(3//4, 5//6)


Out[4]:
Vector2D{Rational{Int64}}(3//4,5//6)

In [6]:
show{T}(io::IO, v::Vector2D{T}) = print(io, "[$(v.x), $(v.y)]")


Out[6]:
show (generic function with 91 methods)

In [7]:
v


Out[7]:
[3//4, 5//6]

Here, the types of the two arguments were different, so there is no match for the type signature.

We can define outer constructors, defined outside the type definition itself, which allow other ways of constructing the object:


In [8]:
Vector2D{T}(x::T) = Vector2D(x, x)


Out[8]:
Vector2D{T<:Real} (constructor with 2 methods)

In [9]:
Vector2D(3)


Out[9]:
Vector2D{Int64}(3,3)

Example: a simple type for a collection of particles

Let's define a particle:


In [8]:
type Particle
    position::Vector2D{Float64}
    velocity::Vector2D{Float64}
end

move(p::Particle, dt::Real) = p.position += p.velocity * dt


Out[8]:
move (generic function with 1 method)

In [9]:
show(io::IO, p::Particle) = print(io, "pos: $(p.position); vel: $(p.velocity)")


Out[9]:
show (generic function with 92 methods)

In [11]:
p = Particle(Vector2D(0.,0.), Vector2D(1.,1.))


Out[11]:
pos: [0.0, 0.0]; vel: [1.0, 1.0]

In [13]:
+{T}(v1::Vector2D{T}, v2::Vector2D{T}) = Vector2D{T}(v1.x+v2.x, v1.y+v2.y)

*{T}(v::Vector2D{T}, lamb::Number)  = Vector2D{T}(lamb*v.x, lamb*v.y)


Out[13]:
* (generic function with 127 methods)

In [14]:
move(p, 0.1)


Out[14]:
[0.1, 0.1]

In [8]:
p


Out[8]:
Particle(Vector2D(0.1,0.1),Vector2D(1.0,1.0))

Now we can define a gas as a collection of particle:


In [15]:
Int


Out[15]:
Int64

In [16]:
type Gas
    particles::Vector{Particle}  # Array{Particle, 1}
    
    function Gas(N::Integer)
        parts = [Particle(Vector2D(rand(2)...), Vector2D(rand(2)...)) for i in 1:N]
        new(parts)
    end
end

In [17]:
show(io::IO, g::Gas) = for i in 1:length(g.particles); \
    println(io, "Particle $i: $(g.particles[i])"); end


Out[17]:
show (generic function with 93 methods)

In [18]:
g = Gas(10)


Out[18]:
Particle 1: pos: [0.8401571871406985, 0.18856970525763184]; vel: [0.4596812641022978, 0.5784262750724491]
Particle 2: pos: [0.31451484655671647, 0.10567720577699169]; vel: [0.6793346556536703, 0.7043142026390625]
Particle 3: pos: [0.2837859636931628, 0.5789334209946704]; vel: [0.6970907948612055, 0.9252322283977674]
Particle 4: pos: [0.4880527858855739, 0.6011994939455119]; vel: [0.27086791922118336, 0.7983654060058591]
Particle 5: pos: [0.40422329467131, 0.4167640334568994]; vel: [0.17875915401147457, 0.8245688498769441]
Particle 6: pos: [0.11205564713828187, 0.31206386913314965]; vel: [0.9344556687726897, 0.10661012636906952]
Particle 7: pos: [0.758378072195554, 0.296551074205055]; vel: [0.24019765986222263, 0.19659517334941445]
Particle 8: pos: [0.19922196169683493, 0.5900826738906546]; vel: [0.2936470240291018, 0.6600190957249954]
Particle 9: pos: [0.13252747366692819, 0.7307090616735368]; vel: [0.9020558731460289, 0.8512875803383082]
Particle 10: pos: [0.3379179889713879, 0.06402477243763549]; vel: [0.6014263963042701, 0.22639908858998958]

In [41]:
move(g, 1)
g


Out[41]:
Particle 1: pos: [0.730880319692343, 0.2796501535129359]; vel: [0.011193267298662768, 0.1896808129627281]
Particle 2: pos: [1.16039593789992, 0.9441692275849607]; vel: [0.263429151377901, 0.8468877504970715]
Particle 3: pos: [1.6666067582365627, 0.3961299078605012]; vel: [0.7700748108540991, 0.2196494577690271]
Particle 4: pos: [0.9701729190049899, 0.7843895045657923]; vel: [0.25339292712850914, 0.35521212198092544]
Particle 5: pos: [0.6973622153663408, 1.0810152148402645]; vel: [0.4550143749133051, 0.6443745244169132]
Particle 6: pos: [0.7266153528207528, 0.22939062897384166]; vel: [0.23270614878986695, 0.2170317822421448]
Particle 7: pos: [0.3522289676319774, 1.8952100652781094]; vel: [0.2328368405667145, 0.9154546952395797]
Particle 8: pos: [0.6517052073532643, 0.7954128199341437]; vel: [0.6212587027599834, 0.40434264420206345]
Particle 9: pos: [1.461020849277742, 1.0270123116841756]; vel: [0.7485545114358987, 0.23357706552863133]
Particle 10: pos: [1.3454456302874394, 0.9754278188746057]; vel: [0.7429592498565307, 0.12339036567006523]

In [36]:
function move(g::Gas, dt::Number)
    for particle in g.particles
        move(particle, dt)
    end
end


Out[36]:
move (generic function with 2 methods)

In [99]:
move(g, 1)


[Particle(Vector2D(0.4100545643085276,0.7676363902728662),Vector2D(0.24938626268837427,0.9825967553493955)),Particle(Vector2D(0.2102452108859496,0.889693333563705),Vector2D(0.21287583861363224,0.8068570118314959)),Particle(Vector2D(0.19724340554018993,0.7904963971058772),Vector2D(0.536265203822587,0.9037289864895577)),Particle(Vector2D(0.25780964395756567,0.36770118129693063),Vector2D(0.8062880526148144,0.26950033650622607)),Particle(Vector2D(0.674431498602819,0.6854905990848916),Vector2D(0.7982268753553292,0.9381682737272479)),Particle(Vector2D(0.3107654997497411,0.00916652369829607),Vector2D(0.6903239459974226,0.3335712930840613)),Particle(Vector2D(0.8337757015793896,0.4019794592055861),Vector2D(0.8398063168102692,0.409628854228981)),Particle(Vector2D(0.8886642578985902,0.2662466340462406),Vector2D(0.36997149382773076,0.012723333186220875)),Particle(Vector2D(0.2980807091871105,0.4647730476022649),Vector2D(0.4908256919109293,0.1966075391583828)),Particle(Vector2D(0.9310095003592627,0.7354528651044734),Vector2D(0.9694676029513127,0.7690493773372564))]

In [100]:
g


Particle(
Out[100]:

Vector2D(0.6594408269969019,1.7502331456222617),Vector2D(0.24938626268837427,0.9825967553493955))
Particle(Vector2D(0.42312104949958185,1.6965503453952009),Vector2D(0.21287583861363224,0.8068570118314959))
Particle(Vector2D(0.733508609362777,1.6942253835954348),Vector2D(0.536265203822587,0.9037289864895577))
Particle(Vector2D(1.06409769657238,0.6372015178031567),Vector2D(0.8062880526148144,0.26950033650622607))
Particle(Vector2D(1.4726583739581482,1.6236588728121395),Vector2D(0.7982268753553292,0.9381682737272479))
Particle(Vector2D(1.0010894457471637,0.3427378167823574),Vector2D(0.6903239459974226,0.3335712930840613))
Particle(Vector2D(1.6735820183896588,0.8116083134345671),Vector2D(0.8398063168102692,0.409628854228981))
Particle(Vector2D(1.258635751726321,0.2789699672324615),Vector2D(0.36997149382773076,0.012723333186220875))
Particle(Vector2D(0.7889064010980398,0.6613805867606477),Vector2D(0.4908256919109293,0.1966075391583828))
Particle(Vector2D(1.9004771033105754,1.5045022424417298),Vector2D(0.9694676029513127,0.7690493773372564))

Matrix multplication


In [23]:
M = [1 1; 0 1]


Out[23]:
2x2 Array{Int64,2}:
 1  1
 0  1

In [24]:
M * M


Out[24]:
2x2 Array{Int64,2}:
 1  2
 0  1

In [25]:
M^10


Out[25]:
2x2 Array{Int64,2}:
 1  10
 0   1

In [27]:
M^(-1)


Out[27]:
2x2 Array{Float64,2}:
 1.0  -1.0
 0.0   1.0

In [29]:
inv(M)


Out[29]:
2x2 Array{Float64,2}:
 1.0  -1.0
 0.0   1.0

In [30]:
det(M)


Out[30]:
1

In [31]:
norm(M)


Out[31]:
1.618033988749895

In [32]:
?norm


Base.norm(A[, p])

   Compute the "p"-norm of a vector or the operator norm of a matrix
   "A", defaulting to the "p=2"-norm.

   For vectors, "p" can assume any numeric value (even though not
   all values produce a mathematically valid vector norm). In
   particular, "norm(A, Inf)" returns the largest value in
   "abs(A)", whereas "norm(A, -Inf)" returns the smallest.

   For matrices, valid values of "p" are "1", "2", or "Inf".
   (Note that for sparse matrices, "p=2" is currently not
   implemented.) Use "vecnorm()" to compute the Frobenius norm.

In [34]:
lamb, vv = eig(M)


Out[34]:
([1.0,1.0],
2x2 Array{Float64,2}:
 1.0  -1.0        
 0.0   2.22045e-16)

In [23]:
methods(Symmetric)


Out[23]:
3 methods for generic function Symmetric:

Eigenvalues of a random matrix


Exercise: Generate a random matrix of $1000 \times 1000$ gaussian random variates. Calculate its eigenvalues and plot them. Calculate the differences between consecutive eigenvalues and plot a histogram of them.



In [15]:
N = 1000
M = randn(N, N)
M = Symmetric(M);

In [16]:
typeof(M)


Out[16]:
Symmetric{Float64} (constructor with 2 methods)

In [20]:
@which dot([3], [4])


Out[20]:
dot(x::AbstractArray{T,1},y::AbstractArray{T,1}) at linalg/matmul.jl:49

In [19]:
help("dot")


INFO: Loading help data...
Base.dot(x, y)

   Compute the dot product. For complex vectors, the first vector is
   conjugated.

Base.LinAlg.BLAS.dot(n, X, incx, Y, incy)

   Dot product of two vectors consisting of "n" elements of array
   "X" with stride "incx" and "n" elements of array "Y" with
   stride "incy".

In [17]:
@time lamb, vv = eig(M);


elapsed time: 0.495310114 seconds (24377616 bytes allocated)

In [13]:
using PyPlot


INFO: Loading help data...

In [18]:
plot(lamb, "o-")


Out[18]:
1-element Array{Any,1}:
 PyObject <matplotlib.lines.Line2D object at 0x10a503250>

In [50]:
PyPlot.figure(figsize=(8,4))
plot(lamb, "o-")


Out[50]:
1-element Array{Any,1}:
 PyObject <matplotlib.lines.Line2D object at 0x12739cad0>

In [22]:
differences = diff(lamb);

In [23]:
plot(differences, "o-")


Out[23]:
1-element Array{Any,1}:
 PyObject <matplotlib.lines.Line2D object at 0x1039fe650>

In [53]:
h = hist(d, 100)


Out[53]:
(0.0:0.002:0.14400000000000002,[23,67,129,145,186,148,169,163,133,136  …  0,0,0,0,0,0,0,0,0,1])

In [59]:
plot(collect(h[1][1:end-1]), h[2])


Out[59]:
1-element Array{Any,1}:
 PyObject <matplotlib.lines.Line2D object at 0x127a18350>

requires vs include vs using vs import


In [70]:
g.particles


Out[70]:
10-element Array{Particle,1}:
 Particle(Vector2D(1.1970706607995785,0.9626230979634414),Vector2D(0.860883456513649,0.6912433760368852))    
 Particle(Vector2D(1.053173102651149,0.1511931905677396),Vector2D(0.8340780458653039,0.25711513963745936))   
 Particle(Vector2D(0.23418507182780868,0.1636419234893668),Vector2D(0.5955322025693717,0.24991956880512323)) 
 Particle(Vector2D(0.42255575858509486,0.5273931990785453),Vector2D(0.2006799940853723,0.6328159954800312))  
 Particle(Vector2D(0.3068915889399675,0.13605825532312857),Vector2D(0.43637626808391783,0.18840541521552945))
 Particle(Vector2D(1.261065364493417,0.7019570824715238),Vector2D(0.8829407354236436,0.8559843409264631))    
 Particle(Vector2D(0.19304010783643638,0.6135945878339716),Vector2D(0.5699319437166632,0.633292636020014))   
 Particle(Vector2D(0.6975851395549426,0.35822475426018596),Vector2D(0.9632833403270651,0.6328280131492559))  
 Particle(Vector2D(1.1112601539035263,0.5851179879294491),Vector2D(0.9151617509797421,0.664341462715691))    
 Particle(Vector2D(0.3128717288502572,1.2580516751593864),Vector2D(0.37515387127035216,0.9028796885418442))  

In [71]:
for particle in g.particles
    move(particle, 1)
end

g.particles


Out[71]:
10-element Array{Particle,1}:
 Particle(Vector2D(2.057954117313227,1.6538664740003266),Vector2D(0.860883456513649,0.6912433760368852))   
 Particle(Vector2D(1.887251148516453,0.40830833020519897),Vector2D(0.8340780458653039,0.25711513963745936))
 Particle(Vector2D(0.8297172743971803,0.41356149229449),Vector2D(0.5955322025693717,0.24991956880512323))  
 Particle(Vector2D(0.6232357526704672,1.1602091945585764),Vector2D(0.2006799940853723,0.6328159954800312)) 
 Particle(Vector2D(0.7432678570238853,0.324463670538658),Vector2D(0.43637626808391783,0.18840541521552945))
 Particle(Vector2D(2.1440060999170605,1.557941423397987),Vector2D(0.8829407354236436,0.8559843409264631))  
 Particle(Vector2D(0.7629720515530996,1.2468872238539856),Vector2D(0.5699319437166632,0.633292636020014))  
 Particle(Vector2D(1.6608684798820077,0.9910527674094418),Vector2D(0.9632833403270651,0.6328280131492559)) 
 Particle(Vector2D(2.0264219048832683,1.2494594506451402),Vector2D(0.9151617509797421,0.664341462715691))  
 Particle(Vector2D(0.6880256001206093,2.1609313637012306),Vector2D(0.37515387127035216,0.9028796885418442))